package com.ltcode.auth.domain.model;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.Set;

/**
 * 登录会话领域模型
 * 
 * @author ltcode
 * @since 2024-01-01
 */
@Data
public class LoginSession implements Serializable {
    
    private static final long serialVersionUID = 1L;

    /** 会话ID */
    private String sessionId;

    /** 用户信息 */
    private AuthUser user;

    /** 访问令牌 */
    private AuthToken accessToken;

    /** 刷新令牌 */
    private AuthToken refreshToken;

    /** 登录IP */
    private String loginIp;

    /** 登录时间 */
    private Date loginTime;

    /** 最后访问时间 */
    private Date lastAccessTime;


    /** 会话状态 */
    private SessionStatus status;

    /** 权限列表 */
    private Set<String> permissions;

    /** 角色列表 */
    private Set<String> roles;

    /**
     * 会话状态枚举
     */
    public enum SessionStatus {
        ACTIVE("active", "活跃"),
        EXPIRED("expired", "已过期"),
        LOGOUT("logout", "已登出"),
        KICKED("kicked", "被踢出");

        private final String code;
        private final String description;

        SessionStatus(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 检查会话是否有效
     */
    public boolean isValid() {
        return SessionStatus.ACTIVE.equals(status) && 
               accessToken != null && 
               accessToken.isValid();
    }

    /**
     * 更新最后访问时间
     */
    public void updateLastAccessTime() {
        this.lastAccessTime = new Date();
    }

    /**
     * 刷新访问令牌
     */
    public void refreshAccessToken(AuthToken newAccessToken) {
        this.accessToken = newAccessToken;
        updateLastAccessTime();
    }

    /**
     * 登出会话
     */
    public void logout() {
        this.status = SessionStatus.LOGOUT;
        if (this.accessToken != null) {
            this.accessToken.revoke();
        }
        if (this.refreshToken != null) {
            this.refreshToken.revoke();
        }
    }

    /**
     * 踢出会话
     */
    public void kick() {
        this.status = SessionStatus.KICKED;
        if (this.accessToken != null) {
            this.accessToken.revoke();
        }
        if (this.refreshToken != null) {
            this.refreshToken.revoke();
        }
    }

    /**
     * 标记会话过期
     */
    public void markExpired() {
        this.status = SessionStatus.EXPIRED;
        if (this.accessToken != null) {
            this.accessToken.markExpired();
        }
        if (this.refreshToken != null) {
            this.refreshToken.markExpired();
        }
    }

    /**
     * 检查是否需要刷新令牌
     */
    public boolean needRefreshToken(long totalExpireMinutes) {
        return accessToken != null && accessToken.needRefresh(totalExpireMinutes);
    }

    /**
     * 创建登录会话
     */
    public static LoginSession create(String sessionId, AuthUser user, AuthToken accessToken, 
                                    AuthToken refreshToken, String loginIp) {
        LoginSession session = new LoginSession();
        session.setSessionId(sessionId);
        session.setUser(user);
        session.setAccessToken(accessToken);
        session.setRefreshToken(refreshToken);
        session.setLoginIp(loginIp);
        session.setLoginTime(new Date());
        session.setLastAccessTime(new Date());
        session.setStatus(SessionStatus.ACTIVE);
        session.setPermissions(user.getPermissions());
        session.setRoles(user.getRoles());
        return session;
    }

    /**
     * 获取用户ID
     */
    public Long getUserId() {
        return user != null ? user.getId() : null;
    }

    /**
     * 获取用户名
     */
    public String getUsername() {
        return user != null ? user.getUsername() : null;
    }

    /**
     * 检查是否有指定权限
     */
    public boolean hasPermission(String permission) {
        return permissions != null && permissions.contains(permission);
    }

    /**
     * 检查是否有指定角色
     */
    public boolean hasRole(String role) {
        return roles != null && roles.contains(role);
    }

    /**
     * 检查是否为管理员
     */
    public boolean isAdmin() {
        return user != null && user.isAdmin();
    }
}
